#include <opencv2/opencv.hpp>
#include <dlib/opencv.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing.h>
#include <nadjieb/mjpeg_streamer.hpp>
#include <chrono>
#include <iomanip>
#include <thread>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <utility>
#include "FaceRecognizer.h"
#include "PerformanceTimer.h"
#include <fstream>
#include <map>
#include <csignal>
#include <atomic>
#include <iostream>

using namespace std;
using namespace dlib;
using namespace std::chrono;

// 配置参数
#define DETECTION_INTERVAL 7   // 每隔多少帧检测一次人脸
#define PORT 8080              // 视频流端口
#define TARGET_FPS 30          // 目标帧率
#define FRAME_BUFFER_SIZE 5    // 帧缓冲区大小（增大以容纳更多结果）
#define WORKER_THREADS 4       // 增加工作线程数量（提高处理能力）


struct VisitorRecord {
    string identity;
    system_clock::time_point arrival;
    system_clock::time_point departure;
    bool active;
};

class VisitorLogger {
public:
    VisitorLogger() {
        logfile_.open("visitor_log.csv", ios::app);
        if (!logfile_) {
            cerr << "无法打开访客日志文件" << endl;
        } else if (logfile_.tellp() == 0) {
            logfile_ << "身份,到达时间,离开时间,停留时间(秒)\n";
        }
        
        checker_thread_ = thread(&VisitorLogger::inactivityChecker, this);
    }
    
    ~VisitorLogger() {
        running_ = false;
        if (checker_thread_.joinable()) {
            checker_thread_.join();
        }
        
        std::lock_guard<std::mutex> lock(mtx_);
        for (auto& kv : visitors_) {
            auto& record = kv.second;
            if (record.active) {
                record.departure = system_clock::now();
                record.active = false;
                auto duration = duration_cast<seconds>(record.departure - record.arrival).count();
                logfile_ << record.identity << "," 
                         << formatTime(record.arrival) << ","
                         << formatTime(record.departure) << ","
                         << duration << "\n";
            }
        }
        logfile_.close();
    }
    
    void logArrival(const string& identity) {
        std::lock_guard<std::mutex> lock(mtx_);
        auto now = system_clock::now();
        
        if (visitors_.find(identity) == visitors_.end()) {
            visitors_[identity] = {identity, now, now, true};
            cout << "[新访客] " << identity << " 到达: " 
                 << formatTime(now) << endl;
        } else if (!visitors_[identity].active) {
            visitors_[identity].arrival = now;
            visitors_[identity].active = true;
            cout << "[访客返回] " << identity << " 再次到达: " 
                 << formatTime(now) << endl;
        }
    }
    
    void logDeparture(const string& identity) {
        std::lock_guard<std::mutex> lock(mtx_);
        auto it = visitors_.find(identity);
        if (it != visitors_.end() && it->second.active) {
            auto now = system_clock::now();
            it->second.departure = now;
            it->second.active = false;
            
            auto duration = duration_cast<seconds>(it->second.departure - it->second.arrival).count();
            
            if (logfile_) {
                logfile_ << identity << "," 
                         << formatTime(it->second.arrival) << ","
                         << formatTime(it->second.departure) << ","
                         << duration << "\n";
                logfile_.flush();
            }
            
            cout << "[访客离开] " << identity << " 停留时间: " 
                 << duration << "秒" << endl;
        }
    }
    
    void checkInactiveVisitors() {
        std::lock_guard<std::mutex> lock(mtx_);
        auto now = system_clock::now();
        const int INACTIVITY_THRESHOLD = 30; 
        
        for (auto& kv : visitors_) {
            auto& record = kv.second;
            if (record.active) {
                auto last_seen = duration_cast<seconds>(now - record.arrival).count();
                if (last_seen > INACTIVITY_THRESHOLD) {
                    logDeparture(record.identity);
                }
            }
        }
    }
    

    void printActiveVisitors() {
        std::lock_guard<std::mutex> lock(mtx_);
        cout << "\n===== 当前活跃访客 =====" << endl;
        for (const auto& kv : visitors_) {
            const auto& record = kv.second;
            if (record.active) {
                auto duration = duration_cast<seconds>(
                    system_clock::now() - record.arrival).count();
                cout << record.identity << " - 已停留: " << duration << "秒" << endl;
            }
        }
        cout << "=======================" << endl;
    }
    
    void printVisitorLog() {
        std::lock_guard<std::mutex> lock(mtx_);
        cout << "\n\n=============================================" << endl;
        cout << "访客日志报告：" << endl;
        cout << "=============================================" << endl;
        
        ifstream logfile("visitor_log.csv");
        if (logfile.is_open()) {
   
            string header;
            getline(logfile, header);
            
  
            cout << left << setw(15) << "身份"
                 << setw(22) << "到达时间"
                 << setw(22) << "离开时间"
                 << "停留时间" << endl;
            cout << string(70, '-') << endl;
            
 
            string line;
            while (getline(logfile, line)) {
     
                stringstream ss(line);
                string identity, arrival, departure, duration;
                
                getline(ss, identity, ',');
                getline(ss, arrival, ',');
                getline(ss, departure, ',');
                getline(ss, duration, ',');
                

                cout << left << setw(15) << identity
                     << setw(22) << arrival
                     << setw(22) << departure
                     << duration << "秒" << endl;
            }
            logfile.close();
        } else {
            cerr << "无法打开访客日志文件" << endl;
        }
        
        cout << "=============================================" << endl;
    }

private:
    std::map<string, VisitorRecord> visitors_;
    std::mutex mtx_;
    ofstream logfile_;
    atomic<bool> running_{true};
    thread checker_thread_;
    

    void inactivityChecker() {
        while (running_) {
            this_thread::sleep_for(seconds(10));
            checkInactiveVisitors();
        }
    }
    

    string formatTime(const system_clock::time_point& tp) {
        time_t t = system_clock::to_time_t(tp);
        tm tm = *localtime(&t);
        ostringstream oss;
        oss << put_time(&tm, "%Y-%m-%d %H:%M:%S");
        return oss.str();
    }
};

atomic<bool> running(true);


void signalHandler(int signum) {
    if (signum == SIGINT) {
        running = false;
    }
}


class FrameQueue {
public:
    void push(const cv::Mat& frame, int frame_id) {
        std::unique_lock<std::mutex> lock(mtx_);
        queue_.push(make_pair(frame.clone(), frame_id));
        cond_.notify_one();
    }

    bool pop(cv::Mat& frame, int& frame_id) {
        std::unique_lock<std::mutex> lock(mtx_);
        if (cond_.wait_for(lock, 10ms, [this] { return !queue_.empty() || !running; })) {
            if (!queue_.empty()) {
                auto item = queue_.front();
                frame = item.first;
                frame_id = item.second;
                queue_.pop();
                return true;
            }
        }
        return false;
    }

    size_t size() {
        std::unique_lock<std::mutex> lock(mtx_);
        return queue_.size();
    }

private:
    std::queue<std::pair<cv::Mat, int>> queue_;
    std::mutex mtx_;
    std::condition_variable cond_;
};


class ResultCache {
public:
    void update(int frame_id, const std::vector<std::pair<dlib::rectangle, string>>& results) {
        std::lock_guard<std::mutex> lock(mtx_);
        cache_[frame_id] = results;
        

        while (cache_.size() > FRAME_BUFFER_SIZE) {
            cache_.erase(cache_.begin());
        }
    }

    bool getNearest(int target_frame_id, std::vector<std::pair<dlib::rectangle, string>>& results) {
        std::lock_guard<std::mutex> lock(mtx_);
        if (cache_.empty()) return false;
        

        auto best_match = cache_.end();
        int min_diff = INT_MAX;
        
        for (auto it = cache_.begin(); it != cache_.end(); ++it) {
            int diff = abs(it->first - target_frame_id);
            if (diff < min_diff) {
                min_diff = diff;
                best_match = it;
            }
        }
        
        if (best_match != cache_.end()) {
            results = best_match->second;
            return true;
        }
        return false;
    }

private:
    std::map<int, std::vector<std::pair<dlib::rectangle, string>>> cache_;
    std::mutex mtx_;
};


std::map<string, string> loadConfig(const string& configPath) {
    std::map<string, string> config;
    ifstream file(configPath);
    if (!file) {
        cerr << "无法打开配置文件: " << configPath << endl;
        return config;
    }

    string line;
    while (getline(file, line)) {
        size_t pos = line.find('=');
        if (pos != string::npos) {
            string key = line.substr(0, pos);
            string value = line.substr(pos + 1);
            config[key] = value;
        }
    }
    return config;
}


dlib::matrix<dlib::rgb_pixel> convert_to_rgb_matrix(const dlib::cv_image<dlib::bgr_pixel>& img) {
    dlib::matrix<dlib::rgb_pixel> rgb_img;
    dlib::assign_image(rgb_img, dlib::mat(img));
    return rgb_img;
}


string getLocalIP() {
    FILE* pipe = popen("hostname -I | awk '{print $1}'", "r");
    if (!pipe) return "无法获取IP";
    
    char buffer[128];
    string result = "";
    if (fgets(buffer, sizeof(buffer), pipe)) {
        result = buffer;

        if (!result.empty() && result[result.size()-1] == '\n') {
            result.erase(result.size()-1);
        }
    }
    pclose(pipe);
    return result.empty() ? "无法获取IP" : result;
}


void workerThread(FaceRecognizer* recognizer, FrameQueue* frameQueue, 
                 ResultCache* resultCache, atomic<bool>* running) {
    while (*running || frameQueue->size() > 0) {
        cv::Mat frame;
        int frame_id;
        if (frameQueue->pop(frame, frame_id)) {
            try {

                dlib::cv_image<dlib::bgr_pixel> dlib_img(frame);
                dlib::matrix<dlib::rgb_pixel> rgb_img = convert_to_rgb_matrix(dlib_img);
                

                std::vector<dlib::rectangle> faces = recognizer->detectFaces(rgb_img);
                
                std::vector<std::pair<dlib::rectangle, string>> results;
                

                for (const auto& face : faces) {

                    dlib::matrix<dlib::rgb_pixel> face_chip = recognizer->alignFace(rgb_img, face);
                    

                    string identity = recognizer->recognizeFace(face_chip);
                    
                    results.emplace_back(face, identity);
                }
                

                resultCache->update(frame_id, results);
                

                cout << "工作线程: 处理帧 " << frame_id 
                     << ", 检测到 " << faces.size() << " 个人脸" 
                     << endl;
                
            } catch (const exception& e) {
                cerr << "人脸处理错误: " << e.what() << endl;
            }
        }
    }
}

int main() {

    signal(SIGINT, signalHandler);
    

    string localIP = getLocalIP();
    

    const string configPath = "/home/hhy212306170/practice/dlib/s5/config.txt";
    std::map<string, string> config = loadConfig(configPath);
    if (config.empty()) {
        cerr << "配置文件加载失败或为空" << endl;
        return -1;
    }


    FaceRecognizer faceRecognizer(config);
    if (!faceRecognizer.initialize()) {
        cerr << "人脸识别器初始化失败" << endl;
        return -1;
    }
    faceRecognizer.printFaceLibInfo();


    VisitorLogger visitorLogger;


    cout << "=============================================" << endl;
    cout << "视频流服务已启动，请打开浏览器访问以下地址：" << endl;
    cout << "本地访问: http://localhost:" << PORT << "/bgr" << endl;
    cout << "外部访问: http://" << localIP << ":" << PORT << "/bgr" << endl;
    cout << "=============================================" << endl;
    cout << "按 Ctrl+C 退出程序" << endl;
    cout << "使用 " << WORKER_THREADS << " 个工作线程" << endl;
    cout << "访客记录将保存在 visitor_log.csv" << endl;


    cv::VideoCapture cap(0);
    if (!cap.isOpened()) {
        cerr << "无法打开摄像头" << endl;
        return -1;
    }


    cap.set(cv::CAP_PROP_FRAME_WIDTH, 640);
    cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480);
    cap.set(cv::CAP_PROP_FPS, 30);


    nadjieb::MJPEGStreamer streamer;
    streamer.start(PORT);
    

    std::vector<int> params = {cv::IMWRITE_JPEG_QUALITY, 90};


    FrameQueue frameQueue;
    ResultCache resultCache;
    std::vector<std::thread> workers;
    

    for (int i = 0; i < WORKER_THREADS; i++) {
        workers.emplace_back(workerThread, &faceRecognizer, &frameQueue, &resultCache, &running);
    }


    TimerManager& timerMgr = TimerManager::getInstance();
    auto frameTimer = timerMgr.getOrCreateTimer("帧捕获和处理全过程");
    auto streamTimer = timerMgr.getOrCreateTimer("推流");

    int frame_count = 0;
    double fps = 0;
    auto last_fps_time = steady_clock::now();
    int fps_counter = 0;
    int last_processed_id = -1;
    

    while (running) {
        auto frame_start = steady_clock::now();
        

        frameTimer->start();
        

        cv::Mat frame;
        cap >> frame;
        if (frame.empty()) {
            cerr << "获取帧失败" << endl;
            break;
        }
        

        if (frame_count % DETECTION_INTERVAL == 0) {
            frameQueue.push(frame, frame_count);
            cout << "主线程: 提交帧 " << frame_count << " 到队列" << endl;
        }
        

        std::vector<std::pair<dlib::rectangle, string>> faceResults;
        if (resultCache.getNearest(frame_count, faceResults)) {
            last_processed_id = frame_count;
            cout << "主线程: 获取最接近帧 " << frame_count << " 的结果: " 
                 << faceResults.size() << " 个人脸" << endl;
        } else {
            cout << "主线程: 无可用人脸结果" << endl;
            faceResults.clear();
        }
        

        cv::Mat displayFrame = frame.clone();
        if (displayFrame.channels() == 1) {
            cv::cvtColor(displayFrame, displayFrame, cv::COLOR_GRAY2BGR);
        }
        

        for (const auto& result : faceResults) {
            const dlib::rectangle& face = result.first;
            const string& identity = result.second;
            

            int left = max(0, static_cast<int>(face.left()));
            int top = max(0, static_cast<int>(face.top()));
            int right = min(displayFrame.cols - 1, static_cast<int>(face.right()));
            int bottom = min(displayFrame.rows - 1, static_cast<int>(face.bottom()));
            

            if (left >= right || top >= bottom) {
                cerr << "跳过无效人脸坐标: (" 
                     << left << ", " << top << ", "
                     << right << ", " << bottom << ")"
                     << endl;
                continue;
            }
            

            cv::rectangle(displayFrame, 
                cv::Point(left, top),
                cv::Point(right, bottom),
                cv::Scalar(0, 255, 0), 2);
            

            int textY = top - 10;
            if (textY < 20) textY = bottom + 20;

            cv::putText(displayFrame, identity, 
                        cv::Point(left, textY),
                        cv::FONT_HERSHEY_SIMPLEX, 0.7,
                        cv::Scalar(0, 255, 0), 2);
            

            visitorLogger.logArrival(identity);
        }
        
        string status_str = "Faces: " + to_string(faceResults.size());
        cv::putText(displayFrame, status_str, cv::Point(10, 30), 
                   cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(0, 255, 0), 2);
        
        streamTimer->start();
        std::vector<uchar> buff_bgr;
        cv::imencode(".jpg", displayFrame, buff_bgr, params);
        streamer.publish("/bgr", string(buff_bgr.begin(), buff_bgr.end()));
        streamTimer->end();
        

        frameTimer->end();
        

        fps_counter++;
        auto now = steady_clock::now();
        auto elapsed = duration_cast<milliseconds>(now - last_fps_time).count();
        
        if (elapsed >= 1000) {
            fps = fps_counter * 1000.0 / elapsed;
            fps_counter = 0;
            last_fps_time = now;
            

            cout << "\r当前FPS: " << fixed << setprecision(1) << fps 
                 << " | 队列大小: " << frameQueue.size() 
                 << " | 处理帧: " << last_processed_id << "/" << frame_count << flush;
        }
        
        if (frame_count % 100 == 0) { 
            visitorLogger.printActiveVisitors();
        }
        

        auto frame_end = steady_clock::now();
        auto frame_duration = duration_cast<milliseconds>(frame_end - frame_start).count();
        int target_duration = 1000 / TARGET_FPS;
        
        if (frame_duration < target_duration) {
            int delay = target_duration - frame_duration;
            
        }
        
        frame_count++;
    }


    running = false;
    

    for (auto& worker : workers) {
        if (worker.joinable()) {
            worker.join();
        }
    }
    streamer.stop();
    cap.release();
    

    cout << "\n\n=============================================" << endl;
    cout << "性能统计报告：" << endl;
    cout << "=============================================" << endl;
    timerMgr.printAllSummaries();
    cout << "=============================================" << endl;
    

    visitorLogger.printVisitorLog();
    
    cout << "程序已退出" << endl;
    return 0;
}